package com.yfbao.horizon.service;

import com.yfbao.horizon.model.TestUser;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.io.FileFilter;
import java.lang.reflect.Method;
import java.net.URL;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Set;

public class ClassUtil {

    private static Logger logger = LoggerFactory.getLogger(ClassUtil.class);

    private static final String FILE_TYPE = "file";

    private static final String JAR_TYPE = "jar";

    /**
     * 获取当前线程加载器
     *
     * @return
     */
    public static ClassLoader getClassLoader() {
        return Thread.currentThread().getContextClassLoader();
    }

    /**
     * 加载类
     *
     * @param className
     * @param isInitialized
     * @return
     */
    public static Class<?> loadClass(String className, boolean isInitialized) {
        Class<?> cls = null;
        try {
            cls = Class.forName(className, isInitialized, getClassLoader());
        } catch (ClassNotFoundException e) {
            logger.error("load class failure", e);
            throw new RuntimeException();
        }
        return cls;
    }

    /**
     * 获取指定包下的所有类对象
     *
     * @param packageName
     * @return
     */
    public static Set<Class<?>> getClassSet(String packageName) {
        Set<Class<?>> classSets = new HashSet<Class<?>>(); // 将类信息保存到集合中存储
        try {
// 将包全名称替换为文件路径
            Enumeration<URL> urls = getClassLoader().getResources(packageName.replace(".", "/"));
            while (urls.hasMoreElements()) {
                URL url = urls.nextElement();
// 协议名称，判断文件类型
                String protocol = url.getProtocol();
// 多种文件类型判断，只需增加if即可
                if (FILE_TYPE.equals(protocol)) {
                    String basePath = url.getPath().replace("%20", ""); // 去掉空格
                    addClass(classSets, basePath, packageName); //获取类全路径，并反射加载类
                } else if (JAR_TYPE.equals(protocol)) {
                }
            }
        } catch (Exception e) {
            logger.error("get class set failure", e);
            throw new RuntimeException();
        }
        return classSets;
    }

    /**
     * 扫描文件目录，获取子目录的文件，并执行反射获取类文件信息
     *
     * @param classSets
     * @param basePath
     * @param packageName
     */
    public static void addClass(Set<Class<?>> classSets, String basePath, String packageName) {
        // 获取子目录
        File[] files = new File(basePath).listFiles(new FileFilter() {
            public boolean accept(File file) {
                // 过滤文件，必须为文件且以.class结尾，或者是文件目录
                return ((file.isFile() && file.getName().endsWith(".class")) || (file.isDirectory()));
            }
        });
// 遍历获取文件信息
        for (File file : files) {
            String fileName = file.getName();
// 如果为文件
            if (file.isFile()) {
                String className = fileName.substring(0, fileName.lastIndexOf("."));
                if (StringUtils.isNotEmpty(className)) {
                    className = packageName + "." + className;
                }
                doAddClass(classSets, className);
            } else {
// 获取文件名称，该文件为目录
                String subPath = fileName;
                if (StringUtils.isNotEmpty(subPath)) {
                    subPath = packageName + "/" + subPath;
                }
// 获取包名
                String subPackage = packageName;
                if (StringUtils.isNotEmpty(subPackage)) {
                    subPackage = packageName + "." + fileName;
                }
// 递归遍历文件信息
                addClass(classSets, subPath, subPackage);
            }
        }
    }

    /**
     * 将反射对象添加到集合中
     *
     * @param classSets
     * @param className
     */
    private static void doAddClass(Set<Class<?>> classSets, String className) {
        Class<?> cls = loadClass(className, false);
        classSets.add(cls);
    }


    public static void main(String[] args) {
        JarLoaderUtil testUser = new JarLoaderUtil();
        Method[] methods = testUser.getClass().getMethods();
        for (Method method : methods) {
            System.out.println(method.getName());
            if(method.getName().equals("loopFiles")){
                Class<?>[] parameterTypes = method.getParameterTypes();
                for (Class<?> parameterType : parameterTypes) {
                    System.out.println(parameterType.getName());
                }
            }
        }
    }

    public static Method getMethod(Object obj,String methodName) {
        Method[] methods = obj.getClass().getDeclaredMethods();
        for (Method method : methods) {
            System.out.println(method.getName());
            if(method.getName().equals(methodName)){
                return  method;
//                for (Class<?> parameterType : parameterTypes) {
//                    return  method
//                }

            }
        }
        return null;
    }
}
